package com.wsd.jing.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsd.jing.constant.SystemConstant;
import com.wsd.jing.dto.LoginDTO;
import com.wsd.jing.entity.LoginLog;
import com.wsd.jing.entity.User;
import com.wsd.jing.enums.CodeEnum;
import com.wsd.jing.exception.BusinessException;
import com.wsd.jing.mapper.UserMapper;
import com.wsd.jing.service.ILoginLogService;
import com.wsd.jing.service.ILoginService;
import com.wsd.jing.service.IUserService;
import com.wsd.jing.utils.IpUtil;
import com.wsd.jing.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * All rights Reserved, Designed By www.tom.com
 *
 * @author tom
 * @version 1.0.0
 * @projectName: jing
 * @packageName: com.wsd.jing.service.impl
 * @className: UserServiceImpl
 * @description: 登录服务类
 * @createDate 2022-11-14 10:53
 * @copyright 2022-11-14 10:53 www.tom.com Inc. All rights reserved.
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements ILoginService {

    private final IUserService userService;
    private final ILoginLogService loginLogService;
    private final RedisUtil redisUtil;

    @Value("${log.login}")
    private Boolean isRecordLog;

    @Override
    public SaTokenInfo login(LoginDTO loginDTO, HttpServletRequest httpServletRequest) {
        // 校验验证码
        checkCaptcha(loginDTO);

        User user = userService.getUserByAccount(loginDTO.getAccount());
        if (user != null) {
            if (!user.getStatus()) {
                // 账号被锁定
                throw new BusinessException(CodeEnum.ACCOUNT_LOCKED);
            }
            String decryptPassword = SaSecureUtil.md5BySalt(loginDTO.getPassword(), loginDTO.getAccount());
            if (loginDTO.getAccount().equals(user.getAccount()) && decryptPassword.equals(user.getPassword())) {
                // 登录
                StpUtil.login(user.getId());
                // 登录日志
                recordLog(loginDTO, httpServletRequest);

                SaTokenInfo saTokenInfo = new SaTokenInfo();
                saTokenInfo.setTokenName(StpUtil.getTokenName());
                saTokenInfo.setTokenValue(StpUtil.getTokenValue());
                return saTokenInfo;
            } else {
                // 账号或密码错误
                throw new BusinessException(CodeEnum.ACCOUNT_PASSWORD_FAILED);
            }
        } else {
            // 账号或密码错误
            throw new BusinessException(CodeEnum.ACCOUNT_PASSWORD_FAILED);
        }
    }

    @Override
    public Map getCaptcha() {
        String uuid = IdUtil.simpleUUID();
        // 生成验证码
        CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(500, 200, 4, 100);
        circleCaptcha.setBackground(Color.WHITE);
        Map<String, Object> resultMap = new HashMap<>(2);
        resultMap.put("uuid", uuid);
        resultMap.put("image", circleCaptcha.getImageBase64Data());
        // 验证码存入redis，并设置过期时间为30秒
        redisUtil.set(SystemConstant.REDIS_PREFIX + uuid, circleCaptcha.getCode(), 30);
        return resultMap;
    }

    private void checkCaptcha(LoginDTO loginDTO) {
        Object key = redisUtil.get(SystemConstant.REDIS_PREFIX + loginDTO.getUuid());
        if (ObjectUtil.isNull(key)) {
            throw new BusinessException(CodeEnum.CAPTCHA_EXPIRED);
        }

        if (!StrUtil.equalsIgnoreCase((String) key, loginDTO.getCaptcha())) {
            throw new BusinessException(CodeEnum.CAPTCHA_FAILED);
        }
    }

    private void recordLog(LoginDTO loginDTO, HttpServletRequest httpServletRequest) {
        if (isRecordLog) {
            String ip = IpUtil.getIp(httpServletRequest);
            String osName = IpUtil.getOsName(httpServletRequest);
            String browserName = IpUtil.getBrowserName(httpServletRequest);
            String browserVersion = IpUtil.getBrowserVersion(httpServletRequest);
            String location = IpUtil.getRegion(ip);

            LoginLog loginLog = new LoginLog();
            loginLog.setBrowser(browserName + "_" + browserVersion);
            loginLog.setSystem(osName);
            loginLog.setIp(ip);
            loginLog.setLocation(location);
            loginLog.setCreateTime(LocalDateTime.now());
            loginLog.setAccount(loginDTO.getAccount());
            loginLogService.insertLoginLog(loginLog);
        }
    }
}
